package com.itheima.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.mapper.EmpMapper;
import com.itheima.pojo.*;
import com.itheima.service.DeptService;
import com.itheima.service.EmpExprService;
import com.itheima.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements EmpService {

    @Autowired
    DeptService deptService;
    @Autowired
    EmpExprService empExprService;
    // 分页查询
    @Override
    public PageResult<Emp> getPageResult(EmpQueryParam param) {
        Page<Emp> page = new Page<>(param.getPage(), param.getPageSize());

        // 创建查询条件 利用的是LambdaQueryWrapper 别问了Wrapper的作用是封装查询条件 因为正常的mp实现不了复杂where查询
        LambdaQueryWrapper<Emp> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(param.getName()!=null, Emp::getName, param.getName())
                .eq(param.getGender()!=null,Emp::getGender, param.getGender())
                .between(param.getBegin()!=null&& param.getEnd()!=null, Emp::getEntryDate, param.getBegin(), param.getEnd())
        ;

        page=page(page, queryWrapper);//将配置对象返回给这个配置方法 这个是分页配置方法我们目的是实现这个 只是他需要page对象而已
        //同时 如果我们是进行条件分页查询 我们需要在提供一个参数 因为可能是复杂查询 通过queryWrapper 我们先创建一个queryWrapper对象

//        // 使用lambdaQuery方法构建查询条件 上面的简化版
//        page = lambdaQuery().like(param.getName() != null && !param.getName().isEmpty(), Emp::getName, param.getName())
//                .eq(param.getGender() != null, Emp::getGender, param.getGender())
//                .between(param.getBegin() != null && param.getEnd() != null, Emp::getEntryDate, param.getBegin(), param.getEnd())
//                .page(page);


        //根据最近修改时间降序排序
        page.addOrder(OrderItem.desc("update_time"));

        //改造查询部门名称成问题 解决方法基于多次单表

        List<Emp> emps = page.getRecords();//通过ctrl+alt+v 抽取getRecords数据作为一个records变量
        // 获取所有员工的部门id
        List<Integer> deptIds = emps.stream().map(emp -> emp.getDeptId()).collect(Collectors.toList());

        if (!deptIds.isEmpty()) {
            // 根据部门ID查询部门信息
            List<Dept> depts = deptService.listByIds(deptIds);

            // 遍历所有员工对象的集合对象 查找员工对应的目标名称对应
            emps.forEach(emp -> {//每拿到一个员工信息就全部遍历部门集合 根据这个员工ID去比较每一个部门ID 如果相同 就将部门名称赋给员工对象
                depts.forEach(dept -> {
                    if (emp.getDeptId() != null && emp.getDeptId().equals(dept.getId())) {
                        emp.setDeptName(dept.getName());
                    }
                });
            });
        }

        return new PageResult<>(page.getTotal(), emps);
    }

    // 保存员工
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveEmp(Emp emp) {
        //保存基础属性
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        // 保存员工基本信息
        save( emp);
        //2.保存员工经历信息
        //首先要获取到我们输入的员工工作经历
        List<EmpExpr> exprList = emp.getExprList();//因为emp中有list类型字段 前端也直接将他作为集合传递过去了 这里直接获取
        if (!exprList.isEmpty()) {//将每一个经历都设置保存操作的该员工ID 即 说明保存这些经历的人是同一个人就是emp获取到的这个人ID 设置他为外键 当然事实也就是这样
            exprList.forEach(expr -> {
                expr.setEmpId(emp.getId());

            });
            //批量保存经历
            empExprService.saveBatch(exprList);
        }
//        在save方法中，你使用@RequestBody Emp emp接收前端传递的 JSON 数据。SpringMVC 会自动将 JSON 中的exprList数组，
//        转换为Emp对象中的List<EmpExpr>集合：

    }

    // 根据员工ID查询员工信息 然后修改信息
    @Override
    public Emp getEmpById(Integer id) {
        //首先进行回显操作
        Emp emp = getById(id);//通过mp操作获取员工信息
        //在该员工信息表中存入我们修改添加后的员工经历信息  emp通过mp操作查询添加后经历集合信息 然后存入emp的list中 在mp的list里面写的是Wrapper构建器满足复杂查询 查询到所有满足
        //员工ID等于经历ID即已经成功添加的经历信息
        emp.setExprList(empExprService.list(new LambdaQueryWrapper<EmpExpr>().eq(EmpExpr::getEmpId, id)));
        return emp;
    }

    // 修改员工信息
    @Override
    public void updateEmp(Emp emp) {
        //1.保存员工基本信息
        emp.setUpdateTime(LocalDateTime.now());
        updateById( emp);
        //3.删除原本的工作经历信息 思路是删除所有员工ID等于当前员工ID的记录 我们直接在保存后删除匹配到的所有记录，避免新旧经历重复
        //empExSer..是EmpExprService接口的实现类（继承了 MyBatis-Plus 的IService），提供了remove等 CRUD 方法
        // remove是IService提供的默认方法，作用是 “根据条件删除表中的记录”，参数需要传入一个 “条件构造器”
        empExprService.remove(new LambdaQueryWrapper<EmpExpr>().eq(EmpExpr::getEmpId, emp.getId()));

//        为什么不用removeById？
//        MyBatis-Plus 还提供了removeById（根据主键删除），但这里不能用，因为：
//        removeById需要传入emp_expr表的主键（比如id字段），而我们只知道 “员工 ID”（emp_id，非主键）；
//        我们需要删除 “一个员工的所有经历”（可能有多条），而removeById只能删除单条记录。

        //3.保存我们新录入的工作经历为准
        List<EmpExpr> exprList = emp.getExprList();//因为emp中有list类型字段 前端也直接将他作为集合传递过去了 这里直接获取
        if (!exprList.isEmpty()) {//将每一个经历都设置保存操作的该员工ID 即 说明保存这些经历的人是同一个人就是emp获取到的这个人ID 设置他为外键 当然事实也就是这样
            exprList.forEach(expr -> {
                expr.setEmpId(emp.getId());

            });
            //批量保存经历
            empExprService.saveBatch(exprList);
        }

    }

    //删除员工 包括经历 依旧分开删除
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeEmpByIds(List<Integer> ids) {
        //删除员工信息
        removeByIds(ids);
        //删除员工工作经历信息 通过remove中的构建器匹配 删除匹配到的所有数据
        empExprService.remove(new LambdaQueryWrapper<EmpExpr>().in(EmpExpr::getEmpId, ids));
        //简写
//        empExprService.remove(Wrappers.)

    }
}
